﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Windows.Forms;
using Scriptor.Presentation.Entity;
using Scriptor.Presentation.Enumerator;

namespace Scriptor.Presentation
{
    public partial class frmWizardProperties : Form
    {
        public List<Entidade> listaEntidade { get; set; }
        List<string> lstString { get; set; }
        List<string> lstTipados { get; set; }
        List<string> lstEnums { get; set; }
        public List<Enumeradores> lstEnumerators { get; set; }

        public frmWizardProperties()
        {
            InitializeComponent();
        }

        private void PropertiesCad_Load(object sender, EventArgs e)
        {
            this.GenerateListEntidade();

            lstString = new List<string>();

            lstString.Add("System.SByte");
            lstString.Add("System.Byte");
            lstString.Add("System.Char");
            lstString.Add("System.Single");
            lstString.Add("System.Decimal");
            lstString.Add("System.Double");
            lstString.Add("System.UInt16");
            lstString.Add("System.UInt32");
            lstString.Add("System.Int32");
            lstString.Add("System.UInt64");
            lstString.Add("System.Int64");
            lstString.Add("System.Boolean");
            lstString.Add("System.String");
            lstString.Add("System.Object");
            lstString.Add("System.DateTime");

            lstString.Add("Nullable<System.Decimal>");
            lstString.Add("Nullable<System.Double>");
            lstString.Add("Nullable<System.Int32>");
            lstString.Add("Nullable<System.Int64>");
            lstString.Add("Nullable<System.Boolean>");
            lstString.Add("Nullable<System.DateTime>");

            this.cmbTipos.DataSource = lstString;

            this.lstEntidades.SelectedIndex = 0;

            if(this.lstEnumerators != null)
                this.PreencherArvoreEnums();

            this.txtNomePropriedade.Focus();

        }

        private void PreencherArvoreEnums()
        {
            foreach (Enumeradores enumPai in this.lstEnumerators)
            {
                tvEnum.Nodes[0].Nodes.Add(enumPai.nomeEnum, enumPai.nomeEnum);
                tvEnum.Nodes[0].Nodes[enumPai.nomeEnum].Tag = enumPai;

                foreach (object propriedade in enumPai.itemsEnum)
                {
                    tvEnum.Nodes[0].Nodes[enumPai.nomeEnum].Nodes.Add(propriedade.ToString(), propriedade.ToString());
                    tvEnum.Nodes[0].Nodes[enumPai.nomeEnum].Nodes[propriedade.ToString()].Tag = enumPai;
                }
                
                tvEnum.Nodes[0].Nodes[enumPai.nomeEnum].ExpandAll();

            }

            this.tvEnum.Nodes[0].ExpandAll();

        }

        private void GenerateListEntidade()
        {
            foreach (Entidade ent in listaEntidade)
            {
                lstEntidades.Items.Add(ent.Sentido.ToString().PadRight(10) + " - " + ent.NomeEntidade);
            }
        }

        private void rbTiposC_CheckedChanged(object sender, EventArgs e)
        {
            txtCompositeNameType.Visible = false;
            cmbTipos.Visible = true;
            this.cmbTipos.DataSource = lstString;
        }

        private void rbTipados_CheckedChanged(object sender, EventArgs e)
        {
            txtCompositeNameType.Visible = false;
            cmbTipos.Visible = true;
            lstTipados = new List<string>();

            foreach (Entidade ent in listaEntidade)
            {
                lstTipados.Add(ent.NomeEntidade);
            }

            this.cmbTipos.DataSource = lstTipados;
        }

        private void btnAddEnum_Click(object sender, EventArgs e)
        {
            TreeNodeCollection tnc = tvEnum.Nodes[0].Nodes;

            bool enumRepetido = false;
            foreach (TreeNode node in tnc)
            {
                if (node.Text == txtEnumName.Text)
                    enumRepetido = true;
            }

            if (!enumRepetido)
            {
                TreeNodeCollection tnC = tvEnum.Nodes[0].Nodes;

                foreach (TreeNode node in tnC)
                {
                    if (node.BackColor == Color.Yellow)
                        node.BackColor = Color.Transparent;
                }

                Enumeradores en = new Enumeradores(txtEnumName.Text);
                tvEnum.Nodes[0].Nodes.Add(en.nomeEnum,en.nomeEnum);
                tvEnum.Nodes[0].Nodes[en.nomeEnum].Tag = en;
                tvEnum.Nodes[0].Nodes[en.nomeEnum].BackColor = Color.Yellow;
                
                if (lstEnumerators == null)
                    lstEnumerators = new List<Enumeradores>();
                
                lstEnumerators.Add(en);
            }
            else
                MessageBox.Show("Enum já cadastrado.", "Enum já cadastrado.");

            txtEnumName.Text = string.Empty;

            tvEnum.Nodes[0].ExpandAll();

            txtEnumItemName.Focus();

        }

        private void rbEnum_CheckedChanged(object sender, EventArgs e)
        {
            lstEnums = new List<string>();
            txtCompositeNameType.Visible = false;
            cmbTipos.Visible = true;

            if (lstEnumerators == null)
                lstEnumerators = new List<Enumeradores>();
            
            foreach (Enumeradores ent in lstEnumerators)
            {
                lstEnums.Add(ent.nomeEnum);
                lstEnums.Add("Nullable<" + ent.nomeEnum + ">");
            }

            this.cmbTipos.DataSource = lstEnums;
        }

        private void btnAddPropriedade_Click(object sender, EventArgs e)
        {
            //Verificar se existe um item selecionado na lista de entidades
            if (lstEntidades.SelectedItem == null)
            {
                MessageBox.Show("Selecione a Entidade.", "ERRO"); 
                return;
            }

            //Verificar se a propriedade tem nome
            if (string.IsNullOrEmpty(txtNomePropriedade.Text))
            {
                MessageBox.Show("Nomeie a propriedade.", "ERRO");
                return;
            }

            //Verificar se a propriedade tem tipo
            if (cmbTipos.SelectedItem == null && txtCompositeNameType.Text==string.Empty)
            {
                MessageBox.Show("Selecione o tipo da propriedade.", "ERRO"); 
                return;
            }

            //Adicionar a propriedade ao objeto entidade
            var elm = listaEntidade.Find(delegate(Entidade x)
            {
                return (x.NomeEntidade == lstEntidades.SelectedItem.ToString().Substring(13)
                    && x.Sentido ==
                    ((Enums.Direction)System.Enum.Parse(typeof(Enums.Direction),
                    lstEntidades.SelectedItem.ToString().Substring(0, lstEntidades.SelectedItem.ToString().IndexOf(" ")))));
            });

            Propriedades prop = null;
            if(rbEnum.Checked)
                prop = new Propriedades(txtNomePropriedade.Text,"Enum." + cmbTipos.SelectedValue.ToString());
            else if (rbComposite.Checked)//Quando o tipo da propriedade for uma composição com outra entidade
            {
                prop = new Propriedades(txtNomePropriedade.Text,"BusinessEntity." + txtCompositeNameType.Text);
                txtCompositeNameType.Text = string.Empty;
            }
            else
                if (rbTipados.Checked)
                {
                    Enums.Direction dir =
                        ((Enums.Direction)System.Enum.Parse(typeof(Enums.Direction),
                    lstEntidades.SelectedItem.ToString().Substring(0, lstEntidades.SelectedItem.ToString().IndexOf(" "))));

                    if (dir == Enums.Direction.Entrada || dir == Enums.Direction.Parameter)
                        prop = new Propriedades(txtNomePropriedade.Text, "DataContract.Request." + cmbTipos.SelectedValue.ToString() + "Request");
                    else
                        if (dir == Enums.Direction.Saida)
                            prop = new Propriedades(txtNomePropriedade.Text, "DataContract.Response." + cmbTipos.SelectedValue.ToString() + "Response");
                }
                else
                    prop = new Propriedades(txtNomePropriedade.Text, cmbTipos.SelectedValue.ToString());

            var propExiste = listaEntidade[lstEntidades.SelectedIndex].ListaPropriedades.Find(delegate(Propriedades x)
            {
                return (x.NomePropriedade == prop.NomePropriedade
                    && x.TipoPropriedade == prop.TipoPropriedade);
            });

            if (propExiste == null)
            {
                listaEntidade[lstEntidades.SelectedIndex].ListaPropriedades.Add(prop);

                //Adicionar a lista de propriedades

                tvProp.Nodes.Clear();
                tvProp.Nodes.Add(elm.NomeEntidade, elm.NomeEntidade);

                foreach (Propriedades propInt in listaEntidade[lstEntidades.SelectedIndex].ListaPropriedades)
                {
                    tvProp.Nodes[0].Nodes.Add(propInt.NomePropriedade, propInt.NomePropriedade + "(" + propInt.TipoPropriedade + ")");
                    tvProp.Nodes[0].Nodes[propInt.NomePropriedade].Tag = propInt;
                }

                tvProp.Nodes[0].ExpandAll();

                txtNomePropriedade.Text = string.Empty;
                txtNomePropriedade.Focus();
            }
            else
            {
                MessageBox.Show("Propriedade já cadastrada.","ERRO");
            }

        }

        private void lstEntidades_SelectedIndexChanged(object sender, EventArgs e)
        {
            PopularPropriedades();
            
        }

        private void PopularPropriedades()
        {
            tvProp.Nodes.Clear();
            tvProp.Nodes.Add(lstEntidades.SelectedItem.ToString().Substring(13));

            List<string> lstEnum = new List<string>();
            foreach (TreeNode node in tvEnum.Nodes[0].Nodes)
            {
                lstEnum.Add(node.Text);
            }

            foreach (Propriedades propInt in listaEntidade[lstEntidades.SelectedIndex].ListaPropriedades)
            {
                if (lstEnum.Contains(propInt.TipoPropriedade))
                    tvProp.Nodes[0].Nodes.Add(propInt.NomePropriedade, propInt.NomePropriedade + "(Enum." + propInt.TipoPropriedade + ")");
                else
                    tvProp.Nodes[0].Nodes.Add(propInt.NomePropriedade, propInt.NomePropriedade + "(" + propInt.TipoPropriedade + ")");

                tvProp.Nodes[0].Nodes[propInt.NomePropriedade].Tag = propInt;
            }

            tvProp.Nodes[0].ExpandAll();

            txtNomePropriedade.Text = string.Empty;
            txtNomePropriedade.Focus();
        }

        private void ctMenu_Opening(object sender, CancelEventArgs e)
        {
            cmbContextMenu.Items.Clear();

            cmbContextMenu.Items.Add("Selecione");

            foreach (Entidade ent in listaEntidade)
            {
                bool EntityHasProperties = (ent.ListaPropriedades.Count() != 0);
                bool SameName = (ent.NomeEntidade == lstEntidades.SelectedItem.ToString().Substring(13));
                bool SameDirection = (ent.Sentido.ToString() == lstEntidades.SelectedItem.ToString().Substring(0, lstEntidades.SelectedItem.ToString().IndexOf(" ")));
                
                if(EntityHasProperties && (!SameName || !SameDirection))
                    cmbContextMenu.Items.Add(ent.Sentido.ToString().PadRight(10) + " - " + ent.NomeEntidade);
            }

            cmbContextMenu.SelectedIndex = 0;
        }

        private void cmbContextMenu_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cmbContextMenu.SelectedIndex == 0) return;

            string source = cmbContextMenu.SelectedItem.ToString();
            string target = lstEntidades.SelectedItem.ToString();
            
            var entidadeSource = listaEntidade.Find(delegate(Entidade x)
            {
                return (x.NomeEntidade == source.Substring(13)
                    && x.Sentido ==
                    ((Enums.Direction)System.Enum.Parse(typeof(Enums.Direction),
                    source.Substring(0, source.IndexOf(" ")))));
            });

            var entidadeTarget = listaEntidade.Find(delegate(Entidade x)
            {
                return (x.NomeEntidade == target.Substring(13)
                    && x.Sentido ==
                    ((Enums.Direction)System.Enum.Parse(typeof(Enums.Direction),
                    target.Substring(0, target.IndexOf(" ")))));
            });

            List<Propriedades> lstPropSource = ((Entidade)entidadeSource).ListaPropriedades;
            List<Propriedades> lstPropTarget = ((Entidade)entidadeTarget).ListaPropriedades;

            if (lstPropTarget.Count == 0)
            {
                CopiarPropriedades(lstPropSource, lstPropTarget,false);
            }
            else
            {
                StringBuilder stb = new StringBuilder();
                stb.Append("Esta Entidade possui propriedades cadastradas.");
                stb.Append(Environment.NewLine);
                stb.Append("Este processo nao poderá ser desfeito.");
                stb.Append(Environment.NewLine);
                stb.Append("Deseja Realmente Substituir as propriedades cadastradas ?");

                DialogResult result = MessageBox.Show(stb.ToString(), "Confirmação", MessageBoxButtons.YesNo);

                if (result == DialogResult.Yes)
                {
                    CopiarPropriedades(lstPropSource, lstPropTarget,true);
                }

            }

            ctMenu.Close();
            PopularPropriedades();

        }

        private static void CopiarPropriedades(List<Propriedades> lstPropSource, List<Propriedades> lstPropTarget, bool LimparListaDestino)
        {
            Propriedades propTemp = null;

            if (LimparListaDestino)
                lstPropTarget.Clear();

            foreach (Propriedades prop in lstPropSource)
            {
                propTemp = new Propriedades(prop.NomePropriedade, prop.TipoPropriedade);
                lstPropTarget.Add(propTemp);
                
            }

        }

        private void lstEntidades_MouseDown(object sender, MouseEventArgs e)
        {
            int indexover = lstEntidades.IndexFromPoint(e.X, e.Y);
            if (indexover >= 0 && indexover < lstEntidades.Items.Count)
            {
                lstEntidades.SelectedIndex = indexover;
            }

        }

        private void tvProp_MouseDown(object sender, MouseEventArgs e)
        {
            tvProp.SelectedNode = tvProp.GetNodeAt(e.X, e.Y);
        }

        private void removerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string target = lstEntidades.SelectedItem.ToString();
            
            var entidadeTarget = listaEntidade.Find(delegate(Entidade x)
            {
                return (x.NomeEntidade == target.Substring(13)
                    && x.Sentido ==
                    ((Enums.Direction)System.Enum.Parse(typeof(Enums.Direction),
                    target.Substring(0, target.IndexOf(" ")))));
            });

            List<Propriedades> lstPropTarget = ((Entidade)entidadeTarget).ListaPropriedades;

            Propriedades prop = new Propriedades(((Propriedades)tvProp.SelectedNode.Tag).NomePropriedade, ((Propriedades)tvProp.SelectedNode.Tag).TipoPropriedade);

            var propIndex = lstPropTarget.FindIndex(delegate(Propriedades x)
            {
                return (x.NomePropriedade == prop.NomePropriedade
                    && x.TipoPropriedade == prop.TipoPropriedade);
            });

            lstPropTarget.RemoveAt(propIndex);

            tvProp.SelectedNode.Remove();

        }

        private void ctListaPropriedades_Opening(object sender, CancelEventArgs e)
        {
            if (tvProp.Nodes[0].IsSelected)
                e.Cancel = true;

            if (tvProp.SelectedNode == null) e.Cancel = true;
        }

        private void tvEnum_MouseDown(object sender, MouseEventArgs e)
        {
            tvEnum.SelectedNode = tvEnum.GetNodeAt(e.X, e.Y);
        }

        private void ctEnum_Opening(object sender, CancelEventArgs e)
        {
            if (tvEnum.Nodes[0].IsSelected)
                e.Cancel = true;

            if (tvEnum.SelectedNode == null) e.Cancel = true;

            enumAtivoToolStripMenuItem.Visible = (tvEnum.SelectedNode.Parent == tvEnum.Nodes[0]);
        }

        private void deletarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (tvEnum.SelectedNode.Parent == tvEnum.Nodes[0])
            {
                if (tvEnum.SelectedNode.GetNodeCount(true) != 0)
                {
                    StringBuilder stb = new StringBuilder();
                    stb.Append("Este Enum possui valores cadastrados.");
                    stb.Append(Environment.NewLine);
                    stb.Append("Este processo nao poderá ser desfeito.");
                    stb.Append(Environment.NewLine);
                    stb.Append("Deseja Realmente exclui-lo ?");

                    DialogResult result = MessageBox.Show(stb.ToString(), "Confirmação", MessageBoxButtons.YesNo);

                    if (result == DialogResult.Yes)
                    {
                        lstEnumerators.Remove((Enumeradores)tvEnum.SelectedNode.Tag);
                        tvEnum.SelectedNode.Remove();
                    }

                }
                else
                {
                    lstEnumerators.Remove((Enumeradores)tvEnum.SelectedNode.Tag);
                    tvEnum.SelectedNode.Remove();
                    txtEnumName.Text = string.Empty;
                    txtEnumName.Focus();
                }
            }
            else
            {
                var Enumerador = lstEnumerators.Find(delegate(Enumeradores x)
                {
                    return (x.nomeEnum == tvEnum.SelectedNode.Parent.Text);
                });

                Enumerador.itemsEnum.Remove(tvEnum.SelectedNode.Text);

                tvEnum.SelectedNode.Remove();

                txtEnumItemName.Text = string.Empty;
                txtEnumItemName.Focus();
            }
        }

        private void enumAtivoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNodeCollection tnC = tvEnum.Nodes[0].Nodes;

            foreach (TreeNode node in tnC)
            {
                if (node.BackColor == Color.Yellow)
                    node.BackColor = Color.Transparent;
            }

            tvEnum.SelectedNode.BackColor = Color.Yellow;

            txtEnumItemName.Focus();

        }

        private void btnAddEnumItem_Click(object sender, EventArgs e)
        {
            string ActiveNode = string.Empty;
            TreeNodeCollection tnC = tvEnum.Nodes[0].Nodes;

            foreach (TreeNode node in tnC)
            {
                if (node.BackColor == Color.Yellow)
                {
                    ActiveNode = node.Text;
                }
            }

            if (string.IsNullOrEmpty(ActiveNode))
            {
                MessageBox.Show("Ative O Enum", "Ative O Enum");
                return;
            }

            if (string.IsNullOrEmpty(txtEnumItemName.Text))
            {
                MessageBox.Show("Informe o nome do Item do Enum", "Informe o nome do Item do Enum");
                return;
            }
            
            var Enumerador = lstEnumerators.Find(delegate(Enumeradores x)
                {
                    return (x.nomeEnum == ActiveNode);
                });

            if (Enumerador.itemsEnum.Contains(txtEnumItemName.Text))
                MessageBox.Show("Item de Enum já cadastrado", "Item de Enum já cadastrado");
            else
            {
                Enumerador.itemsEnum.Add(txtEnumItemName.Text);
                tvEnum.Nodes[0].Nodes[ActiveNode].Nodes.Add(txtEnumItemName.Text, txtEnumItemName.Text);
                tvEnum.Nodes[0].Nodes[ActiveNode].Nodes[txtEnumItemName.Text].Tag = Enumerador;
                tvEnum.Nodes[0].Nodes[ActiveNode].ExpandAll();
                txtEnumItemName.Text = string.Empty;
                txtEnumItemName.Focus();
            }
        }

        private void cmbTipos_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyValue)
            {
                case 49:
                    if (cmbTipos.Items.Contains("System.Int32"))
                    {
                        cmbTipos.SelectedItem = "System.Int32";
                    }
                    break;
                case 50:
                    if (cmbTipos.Items.Contains("System.String"))
                    {
                        cmbTipos.SelectedItem = "System.String";
                    }
                    break;
                case 51:
                    if (cmbTipos.Items.Contains("System.Boolean"))
                    {
                        cmbTipos.SelectedItem = "System.Boolean";
                    }
                    break;
                case 97:
                    if (cmbTipos.Items.Contains("System.Int32"))
                    {
                        cmbTipos.SelectedItem = "System.Int32";
                    }
                    break;
                case 98:
                    if (cmbTipos.Items.Contains("System.String"))
                    {
                        cmbTipos.SelectedItem = "System.String";
                    }
                    break;
                case 99:
                    if (cmbTipos.Items.Contains("System.Boolean"))
                    {
                        cmbTipos.SelectedItem = "System.Boolean";
                    }
                    break;
                default:
                    break;
            }
        }

        private void rbComposite_CheckedChanged(object sender, EventArgs e)
        {
            //Paulo Silva - 14/05/2010
            //Inclui o radion + text para adicionar propriedades que são do tipo de outras entidades (composição)
            cmbTipos.Visible = false;
            txtCompositeNameType.Visible = true;
        }
    }
}